Merge branch 'main' into add-tasks-support
This commit is contained in:
commit
6556e339cb
8 changed files with 756 additions and 194 deletions
9
package-lock.json
generated
9
package-lock.json
generated
|
|
@ -1688,9 +1688,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/diff": {
|
"node_modules/diff": {
|
||||||
"version": "5.2.0",
|
"version": "8.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz",
|
||||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
"integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
|
|
@ -3804,7 +3805,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.25.2",
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
||||||
"diff": "^5.1.0",
|
"diff": "^8.0.3",
|
||||||
"glob": "^10.5.0",
|
"glob": "^10.5.0",
|
||||||
"minimatch": "^10.0.1",
|
"minimatch": "^10.0.1",
|
||||||
"zod-to-json-schema": "^3.23.5"
|
"zod-to-json-schema": "^3.23.5"
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ export const roots: Map<string | undefined, Root[]> = new Map<
|
||||||
*/
|
*/
|
||||||
export const syncRoots = async (server: McpServer, sessionId?: string) => {
|
export const syncRoots = async (server: McpServer, sessionId?: string) => {
|
||||||
const clientCapabilities = server.server.getClientCapabilities() || {};
|
const clientCapabilities = server.server.getClientCapabilities() || {};
|
||||||
const clientSupportsRoots: boolean = clientCapabilities.roots !== undefined;
|
const clientSupportsRoots: boolean = clientCapabilities?.roots !== undefined;
|
||||||
|
|
||||||
// Fetch the roots list for this client
|
// Fetch the roots list for this client
|
||||||
if (clientSupportsRoots) {
|
if (clientSupportsRoots) {
|
||||||
|
|
@ -48,7 +48,7 @@ export const syncRoots = async (server: McpServer, sessionId?: string) => {
|
||||||
{
|
{
|
||||||
level: "info",
|
level: "info",
|
||||||
logger: "everything-server",
|
logger: "everything-server",
|
||||||
data: `Roots updated: ${response.roots.length} root(s) received from client`,
|
data: `Roots updated: ${response?.roots?.length} root(s) received from client`,
|
||||||
},
|
},
|
||||||
sessionId
|
sessionId
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "^1.25.2",
|
"@modelcontextprotocol/sdk": "^1.25.2",
|
||||||
"diff": "^5.1.0",
|
"diff": "^8.0.3",
|
||||||
"glob": "^10.5.0",
|
"glob": "^10.5.0",
|
||||||
"minimatch": "^10.0.1",
|
"minimatch": "^10.0.1",
|
||||||
"zod-to-json-schema": "^3.23.5"
|
"zod-to-json-schema": "^3.23.5"
|
||||||
|
|
|
||||||
|
|
@ -390,5 +390,94 @@ describe('KnowledgeGraphManager', () => {
|
||||||
expect(JSON.parse(lines[0])).toHaveProperty('type', 'entity');
|
expect(JSON.parse(lines[0])).toHaveProperty('type', 'entity');
|
||||||
expect(JSON.parse(lines[1])).toHaveProperty('type', 'relation');
|
expect(JSON.parse(lines[1])).toHaveProperty('type', 'relation');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should strip type field from entities when loading from file', async () => {
|
||||||
|
// Create entities and relations (these get saved with type field)
|
||||||
|
await manager.createEntities([
|
||||||
|
{ name: 'Alice', entityType: 'person', observations: ['test observation'] },
|
||||||
|
{ name: 'Bob', entityType: 'person', observations: [] },
|
||||||
|
]);
|
||||||
|
await manager.createRelations([
|
||||||
|
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Verify file contains type field (order may vary)
|
||||||
|
const fileContent = await fs.readFile(testFilePath, 'utf-8');
|
||||||
|
const fileLines = fileContent.split('\n').filter(line => line.trim());
|
||||||
|
const fileItems = fileLines.map(line => JSON.parse(line));
|
||||||
|
const fileEntity = fileItems.find(item => item.type === 'entity');
|
||||||
|
const fileRelation = fileItems.find(item => item.type === 'relation');
|
||||||
|
expect(fileEntity).toBeDefined();
|
||||||
|
expect(fileEntity).toHaveProperty('type', 'entity');
|
||||||
|
expect(fileRelation).toBeDefined();
|
||||||
|
expect(fileRelation).toHaveProperty('type', 'relation');
|
||||||
|
|
||||||
|
// Create new manager instance to force reload from file
|
||||||
|
const manager2 = new KnowledgeGraphManager(testFilePath);
|
||||||
|
const graph = await manager2.readGraph();
|
||||||
|
|
||||||
|
// Verify loaded entities don't have type field
|
||||||
|
expect(graph.entities).toHaveLength(2);
|
||||||
|
graph.entities.forEach(entity => {
|
||||||
|
expect(entity).not.toHaveProperty('type');
|
||||||
|
expect(entity).toHaveProperty('name');
|
||||||
|
expect(entity).toHaveProperty('entityType');
|
||||||
|
expect(entity).toHaveProperty('observations');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify loaded relations don't have type field
|
||||||
|
expect(graph.relations).toHaveLength(1);
|
||||||
|
graph.relations.forEach(relation => {
|
||||||
|
expect(relation).not.toHaveProperty('type');
|
||||||
|
expect(relation).toHaveProperty('from');
|
||||||
|
expect(relation).toHaveProperty('to');
|
||||||
|
expect(relation).toHaveProperty('relationType');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should strip type field from searchNodes results', async () => {
|
||||||
|
await manager.createEntities([
|
||||||
|
{ name: 'Alice', entityType: 'person', observations: ['works at Acme'] },
|
||||||
|
]);
|
||||||
|
await manager.createRelations([
|
||||||
|
{ from: 'Alice', to: 'Alice', relationType: 'self' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create new manager instance to force reload from file
|
||||||
|
const manager2 = new KnowledgeGraphManager(testFilePath);
|
||||||
|
const result = await manager2.searchNodes('Alice');
|
||||||
|
|
||||||
|
// Verify search results don't have type field
|
||||||
|
expect(result.entities).toHaveLength(1);
|
||||||
|
expect(result.entities[0]).not.toHaveProperty('type');
|
||||||
|
expect(result.entities[0].name).toBe('Alice');
|
||||||
|
|
||||||
|
expect(result.relations).toHaveLength(1);
|
||||||
|
expect(result.relations[0]).not.toHaveProperty('type');
|
||||||
|
expect(result.relations[0].from).toBe('Alice');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should strip type field from openNodes results', async () => {
|
||||||
|
await manager.createEntities([
|
||||||
|
{ name: 'Alice', entityType: 'person', observations: [] },
|
||||||
|
{ name: 'Bob', entityType: 'person', observations: [] },
|
||||||
|
]);
|
||||||
|
await manager.createRelations([
|
||||||
|
{ from: 'Alice', to: 'Bob', relationType: 'knows' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create new manager instance to force reload from file
|
||||||
|
const manager2 = new KnowledgeGraphManager(testFilePath);
|
||||||
|
const result = await manager2.openNodes(['Alice', 'Bob']);
|
||||||
|
|
||||||
|
// Verify open results don't have type field
|
||||||
|
expect(result.entities).toHaveLength(2);
|
||||||
|
result.entities.forEach(entity => {
|
||||||
|
expect(entity).not.toHaveProperty('type');
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.relations).toHaveLength(1);
|
||||||
|
expect(result.relations[0]).not.toHaveProperty('type');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,20 @@ export class KnowledgeGraphManager {
|
||||||
const lines = data.split("\n").filter(line => line.trim() !== "");
|
const lines = data.split("\n").filter(line => line.trim() !== "");
|
||||||
return lines.reduce((graph: KnowledgeGraph, line) => {
|
return lines.reduce((graph: KnowledgeGraph, line) => {
|
||||||
const item = JSON.parse(line);
|
const item = JSON.parse(line);
|
||||||
if (item.type === "entity") graph.entities.push(item as Entity);
|
if (item.type === "entity") {
|
||||||
if (item.type === "relation") graph.relations.push(item as Relation);
|
graph.entities.push({
|
||||||
|
name: item.name,
|
||||||
|
entityType: item.entityType,
|
||||||
|
observations: item.observations
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item.type === "relation") {
|
||||||
|
graph.relations.push({
|
||||||
|
from: item.from,
|
||||||
|
to: item.to,
|
||||||
|
relationType: item.relationType
|
||||||
|
});
|
||||||
|
}
|
||||||
return graph;
|
return graph;
|
||||||
}, { entities: [], relations: [] });
|
}, { entities: [], relations: [] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"mcp>=1.0.0",
|
"mcp>=1.23.0",
|
||||||
"pydantic>=2.0.0",
|
"pydantic>=2.0.0",
|
||||||
"tzdata>=2024.2",
|
"tzdata>=2024.2",
|
||||||
"tzlocal>=5.3.1"
|
"tzlocal>=5.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from tzlocal import get_localzone_name # ← returns "Europe/Paris", etc.
|
||||||
|
|
||||||
from mcp.server import Server
|
from mcp.server import Server
|
||||||
from mcp.server.stdio import stdio_server
|
from mcp.server.stdio import stdio_server
|
||||||
from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource
|
from mcp.types import Tool, TextContent, ImageContent, EmbeddedResource, ErrorData, INVALID_PARAMS
|
||||||
from mcp.shared.exceptions import McpError
|
from mcp.shared.exceptions import McpError
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
@ -54,7 +54,7 @@ def get_zoneinfo(timezone_name: str) -> ZoneInfo:
|
||||||
try:
|
try:
|
||||||
return ZoneInfo(timezone_name)
|
return ZoneInfo(timezone_name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise McpError(f"Invalid timezone: {str(e)}")
|
raise McpError(ErrorData(code=INVALID_PARAMS, message=f"Invalid timezone: {str(e)}"))
|
||||||
|
|
||||||
|
|
||||||
class TimeServer:
|
class TimeServer:
|
||||||
|
|
|
||||||
818
src/time/uv.lock
generated
818
src/time/uv.lock
generated
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue